package com.yang.spingboot.yixincallback.util;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.lang3.StringUtils;
import sun.misc.BASE64Decoder;

import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.spec.SecretKeySpec;
import java.io.IOException;
import java.math.BigInteger;
import java.nio.charset.StandardCharsets;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;

/**
 * AES的加密和解密
 *
 * @author libo
 */
@Slf4j
public class AesUtils {
    //算法
    private static final String ALGORITHMSTR = "AES/ECB/PKCS5Padding";




    public static JSONObject aesSignAndEncrypt(JSONObject srcJson, String time, String appId, String aesKey, String md5Key) throws Exception {
        String string = AesUtils.aesEncrypt(srcJson.toJSONString(), aesKey);
        log.info("aesSignAndEncrypt:{}", string);
        String data = new String(Base64Utils.encode(string), StandardCharsets.UTF_8);
        TreeMap<String, Object> inMap = new TreeMap<String, Object>();
        inMap.put("data", data);
        inMap.put("time", time);
        String sign = createPaySign(inMap, md5Key);
        inMap.put("sign", sign);
        inMap.put("appId", appId);
        log.info("aesSignAndEncrypt output:{}", inMap.toString());
        return new JSONObject(inMap);
    }

    public static JSONObject aesDecryptAndVerifySign(JSONObject srcJson, String aesKey, String md5Key) {
        String srcData = srcJson.getString("data");
        String time = srcJson.getString("time");
        String sign = srcJson.getString("sign");
        TreeMap<String, Object> kvMap = new TreeMap<String, Object>();
        kvMap.put("data", srcData);
        kvMap.put("time", time);
        String dstSign = AesUtils.createPaySign(kvMap, md5Key);
        log.debug("进行签名校验，正确的签名是：[" + dstSign + "]你的签名是：[" + sign + "]");
        if (sign.equals(dstSign)) {
            String dstData = "";
            try {
                dstData = AesUtils.aesDecrypt((new String(Base64Utils.decode(srcData), "utf-8")), aesKey);
                srcJson.put("data", JSON.parseObject(dstData));
                log.debug("解密后请求报文:{}", srcJson.toJSONString());
                return srcJson;
            } catch (Exception e) {
                throw new RuntimeException("报文解密出错。", e);
            }
        } else {
            throw new RuntimeException("签名错误。");
        }
    }


    public static String createPaySign(TreeMap<String, Object> param, String key) {
        String string1 = originalString(param);
        String stringSignTemp = string1 + key;
        log.debug("签名调试输出：" + stringSignTemp);
        String paysign = MD5Utils.MD5(stringSignTemp);
        return paysign;
    }

    private static String originalString(TreeMap<String, Object> treeMap) {
        log.debug("输入对象:{}", JSON.toJSONString(treeMap));
        Set<Map.Entry<String, Object>> entry = treeMap.entrySet();
        StringBuffer sb = new StringBuffer();
        for (Map.Entry<String, Object> obj : entry) {
            String k = obj.getKey();
            String v = String.valueOf(obj.getValue());
            if (StringUtils.isEmpty(v)) {
                continue;
            }
            sb.append(k + "=" + v + "&");
        }
        return sb.toString();
    }


    /**
     * 将byte[]转为各种进制的字符串
     *
     * @param bytes byte[]
     * @param radix 可以转换进制的范围，从Character.MIN_RADIX到Character.MAX_RADIX，超出范围后变为10进制
     * @return 转换后的字符串
     */
    public static String binary(byte[] bytes, int radix) {
        return new BigInteger(1, bytes).toString(radix);// 这里的1代表正数
    }

    /**
     * base 64 encode
     *
     * @param bytes 待编码的byte[]
     * @return 编码后的base 64 code
     */
    public static String base64Encode(byte[] bytes) {
        return Base64.encodeBase64String(bytes);
    }

    /**
     * base 64 decode
     *
     * @param base64Code 待解码的base 64 code
     * @return 解码后的byte[]
     * @throws Exception
     */
    public static byte[] base64Decode(String base64Code) throws IOException {
        return StringUtils.isEmpty(base64Code) ? null : new BASE64Decoder().decodeBuffer(base64Code);
    }


    /**
     * AES加密
     *
     * @param content    待加密的内容
     * @param encryptKey 加密密钥
     * @return 加密后的byte[]
     * @throws Exception
     */
    public static byte[] aesEncryptToBytes(String content, String encryptKey) throws Exception {
        KeyGenerator kgen = KeyGenerator.getInstance("AES");
        kgen.init(128);
        Cipher cipher = Cipher.getInstance(ALGORITHMSTR);
        cipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(encryptKey.getBytes(), "AES"));

        return cipher.doFinal(content.getBytes("utf-8"));
    }


    /**
     * AES加密为base 64 code
     *
     * @param content    待加密的内容
     * @param encryptKey 加密密钥
     * @return 加密后的base 64 code
     * @throws Exception
     */
    public static String aesEncrypt(String content, String encryptKey) throws Exception {
        return base64Encode(aesEncryptToBytes(content, encryptKey));
    }

    /**
     * AES解密
     *
     * @param encryptBytes 待解密的byte[]
     * @param decryptKey   解密密钥
     * @return 解密后的String
     * @throws Exception
     */
    public static String aesDecryptByBytes(byte[] encryptBytes, String decryptKey) throws Exception {
        KeyGenerator kgen = KeyGenerator.getInstance("AES");
        kgen.init(128);

        Cipher cipher = Cipher.getInstance(ALGORITHMSTR);
        cipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec(decryptKey.getBytes(), "AES"));
        byte[] decryptBytes = cipher.doFinal(encryptBytes);
        return new String(decryptBytes);
    }


    /**
     * 将base 64 code AES解密
     *
     * @param encryptStr 待解密的base 64 code
     * @param decryptKey 解密密钥
     * @return 解密后的string
     * @throws Exception
     */
    public static String aesDecrypt(String encryptStr, String decryptKey) throws Exception {
        return StringUtils.isEmpty(encryptStr) ? null : aesDecryptByBytes(base64Decode(encryptStr), decryptKey);
    }

    public static byte[] parseHexStr2Byte(String hexStr) {
        if (hexStr.length() < 1) {
            throw new NullPointerException("the param hexStr(String) is blank");
        }

        byte[] result = new byte[hexStr.length() / 2];
        for (int i = 0; i < hexStr.length() / 2; i++) {
            int high = Integer.parseInt(hexStr.substring(i * 2, i * 2 + 1), 16);
            int low = Integer.parseInt(hexStr.substring(i * 2 + 1, i * 2 + 2), 16);
            result[i] = (byte) (high * 16 + low);
        }

        return result;
    }

    /**
     * 将二进制转换成16进制
     *
     * @param buf 二进制字节数组
     * @return 16进制字符串
     */
    public static String parseByte2HexStr(byte[] buf) {
        StringBuilder sb = new StringBuilder();

        for (byte _byte : buf) {
            String hex = Integer.toHexString(_byte & 0xFF);
            if (hex.length() == 1) {
                hex = '0' + hex;
            }
            sb.append(hex.toUpperCase());
        }
        return sb.toString();
    }

    /**
     * 测试
     */
    public static void main(String[] args) throws Exception {

        String aesKey="cLlMomwrjoE0b5ka";
        //String descri = aesDecrypt("xq7ZQbzEQMkNToO9KN8dkGDB/Wh8fhy/iQsvkuk+Idi6pHLbELPH+UcDpZn8G7Y0pAcT2tXUIalRDoFUuVm4BtMiA+hiJJk5Tk0Ta/ulMlu0u/69kw370kHEzHCGPB5ByaU43mCWgR+abXur6FchAPt/4bRTiEaNUohkbRimtXza6VJrxZFVNB3aQ81sJMC+IrAuCePGVkbDU8O8BYty8HTczmZ9iKqhKSZaGe/s6cBz4Dkydcb1VmoVFX4CaFCtR7TDD+EXsc8k55YFGdtMg4Y6cTjdNVKIOArIGtcR3GvkuOFP6JkF5arw4aY0TVkjnqyFruzcESgSLUo4+tzo6uyCxHtvVzOxIBURqetW13veyAFzlAjjlypsCKRvQ+lKyXa2qpCYOpgCJ8yh9Y/1B7WiHjfHvXir1yJt7NpjhrlZIf3SsJemzzkaa9+VgRngh7HuZ2bx2KnQ9icfEyzHTBIy8TH+s3v9cIJ1E9H/xUWp5xxd0wz0KlHb+1UpocZE1ykDDy9qwF+ixlyIDidndMTW4s8303wNBcCdn8+CThUVFlf4Y/4M4ZjFJqYaiGBogHkfb4SMNV2/Z8jFP5jYhDRekl/pgjPNMYVwrEt09B9RpUS8QP3dVBd80+jurGh9dYAawc06BuaxrfSde9RIdqnE6r6NCbw2Owm8c67aHtin2m5L6k1939+DZUUhWsQwr3DP22fCwWCB3S+jS5LqwaFSFOONbvgMGcwPMizY7BDhYwmI8es/EZoeCxfDs86Dx/fJpdoUzJVqrH9RO6pr3+FjCYjx6z8Rmh4LF8OzzoO1gSyjP1d0+yENBf6qkTBI7Kb6gfZzm4CM2hNyZqX7x29Al1CU0NCFZr8b5Wmc+HsvhGpvRxkb1NHGyxizHSyTzWBxpf3BqyYyX8ggd3tZM5r7VAG+ddhMoWsmTMdDkoMf75lF/WssFt52FdMdiscKhCv0YbID5qIE1SZ/9BtAJbkNCeWYL7Sm4G/nrYjw1m+bXaoovn0ZgainC5yW6eAVfHOPXG5oSSize7OW2FqCazqgkvmxB5dIrT7A0MPiU7eMOHhuMnI5xX7yDDuXrDXJ", aesKey);
        //String descri=aesDecryptByBytes(parseHexStr2Byte("c26fcf4e3ecd28eb12a9b2a4dba81e959963102a089e0ddf303dd393cf3ee59a3952e5c73faac0fa02a0af7da7e8e465569acf2c96b14f7e56730a8e03b52790618f0bfdb1d248b4479ca1624eaa00977e687b1eed753cce1a258b71239543c89c7fed39ecccb171f6b23e0e17fb988ce3c06515cb0aac163277710d5dfde5a704c77c7d78110a24aaf9c3bc5c261ba154840ec712fb5c25090fde254fdba737369a9d26cf6dea5053c3252b43566f15535b8c056dff99f348d918a080cc3025ce7f97e489e24fb0e635badb13761f6cfd4bd5e4805fbaf519ad50a38d2a2c34f0e15c1a4f5e87e576acf91c618a1a767701f1be09b561ef642fc53b59b659bf2a86494d41178a0b970e98e8762b8619dd696a3e7f0645a043a6ef9e0018d7f2447b60003050b5c8d09910796a9f6259846c8c810fdd27e6c0d7d23cc71b43fce24d049c34bacefab6abaeafa2e2d0fcd9ed27e7915e55447ddf468c9a58c03555a60108d0a5834a2a0dd7d16d1ca08cb40e0050a0adc01374771cfaadae93e96a746a05c5d9e1240ae09a92ec0b4b85"),aesKey);
        //String   descri=aesDecryptByBytes(parseHexStr2Byte("4962774235684169456771746A6E73524E6D764152617549542B4C6B62686F5A384E445034505A6B377158442F6D5957332B336858766451362F576E7233445A7532496162776F306D68494B7541714A706B666468684C47677A4F70574D724F5A76367163386C7A6B7A585970595136577469597038584D4A44737A304B4A4845796C515272524B63364838476F47495175794E4C72554745414562692F646F46306B444976376A37486B53586E4B66576B31545A6B7A627355424B7463435A7262394F6A48707A4B6B3033394D792B696C4D6D45497452543938596A7057666E444B65505A72306666724D717862624A61744D576262422F68395A76446169726C7A36484433554D6F665A4762735456586539324465464D6239512F707A466B6C61394141356B46362F61784D566B447A2F2B7334584B5A52763436456A613436666C76516532786F6A4A66365A6630415665753171313766366666744E386247726357626637594F6A46474E4C624F6450665337546231793476584A655868414A796E6E6744713464525A64746A573546674D714C6B47633271343734387762636E476B78565553532F4343423068446F383878315836633069513857442F456868353750414D49732B59577A61716878616D3945696F724C6F56414753743961374C5A72733563467A5066633551783357534A714372624E6151385A582F333535492B2F59355148455731483938564E313845796E764D64756E58315A645630564462763866454D3D"),aesKey);
        //log.info("解密报文:{}", descri);
        //String ss=new String (descri);
        //log.info(aesEncrypt(parseByte2HexStr(ss.getBytes()),aesKey));
        //log.info(parseByte2HexStr(aesEncryptToBytes(ss,aesKey)));
        //String s1="{\"jsCode\":\"013fDnll2l14m84gkpml28zNga0fDnlO\"}";
        //String s1="123";
       // String s2=AesUtils.parseByte2HexStr(s1.getBytes());
//        String s3=AesUtils.aesEncrypt(s1,aesKey);
//        System.out.println(s3);
//        System.out.println(AesUtils.aesDecrypt(s3,aesKey));

        String content="18712a1f88438ed109a11b15ee2b76f0a25e4b45a311e66db6ed7d8f791f6580";
        System.out.println(AesUtils.aesDecryptByBytes(AesUtils.parseHexStr2Byte(content),aesKey));

        /*
        String md5Key = "007ec417439b4118b08cb2d22402d354";
        String aesKey = "16f6a8b4dd044848849c59bdbd0da26a";
        String req = "{\"phone\":\"18511521796\",\"channel\":\"test\"}";
        JSONObject src = JSON.parseObject(req);
        String s1 = String.valueOf(System.currentTimeMillis());
        log.info("time:{}", s1);
        JSONObject result = aesSignAndEncrypt(src, s1,"4182", aesKey, md5Key);
        log.info("加密报文:{}", result.toJSONString());

        JSONObject descri = aesDecryptAndVerifySign(result, aesKey, md5Key);
        log.info("解密报文:{}", descri);

        String s = MD5Utils.MD5("data=eWpSb3NPM20wNUZPb05YaHlyOHRwTXNyNzk1VExndWxxY3VYU3RZUWprZ2N0QjBvRWFZNXVnUTNjaVJrcXpLS0ZHV05KaUJ5Y1ZnMkUyRXFSNHd4bGM4Q1hxaWVYSE92RmY4ZXRJMnRyeFJwRU02Z2lLcWUwVzdwZlVEeU44YnNCYzNkR2pyN042bkZQSFBOZmtxYzdOWEJQM2F5YVpzWEp6ajB2aW1lSGs4PQ==&time=1636438619715&ee31fabcd21f480bbd607caeecd0f7ec");
        log.info("ddddddddddddddd:{}", s);
        */

    }
}